#include "qdeviceclient.h"

#include "qbasedefine.h"

#include "../shared/xmlobject.h"
#include "../shared/qprojectcore.h"
#include "../shared/host/qabstracthost.h"
#include "../shared/property/qabstractproperty.h"

#include <QStringList>

QDeviceClient::QDeviceClient(tagDeviceInfo *info, QObject *parent):
    QObject(parent),
    m_device_info(info),
    m_socket(new QUdpSocket),
    m_send_recv_socket(new QUdpSocket),
    m_timer(new QTimer)
{
    m_socket->bind(CLIENT_HAND_READ,QUdpSocket::ReuseAddressHint);
    m_send_recv_socket->bind(CLIENT_READ,QUdpSocket::ReuseAddressHint);

    m_last_send_time=QDateTime::currentDateTime();

    m_timer->start(30);

    connect(m_socket,SIGNAL(readyRead()),this,SLOT(read()));
    connect(m_send_recv_socket,SIGNAL(readyRead()),this,SLOT(send_read()));
    connect(m_timer,SIGNAL(timeout()),this,SLOT(hand_timer()));
}

QDeviceClient::~QDeviceClient()
{
    QString str=QString::number(DEVICE_OFFLINE_CODE)+":"+m_device_info->m_uuid;
    m_socket->writeDatagram(str.toLocal8Bit(),QHostAddress::Broadcast,CLIENT_HAND_WRITE);
     m_socket->close();
     m_send_recv_socket->close();
     delete m_send_recv_socket;
     delete m_socket;
     delete m_timer;
}

void QDeviceClient::read()
{
    int size=m_socket->pendingDatagramSize();
    if(size<=0)
    {
        return;
    }
    QHostAddress addr;
    char *data=new char[size+1];
    m_socket->readDatagram(data,size,&addr);
    data[size]=0;
    QString buffer=data;
    delete data;
    int index=buffer.indexOf(":");
    QString code=buffer.left(index);
    QString value=buffer.mid(index+1);
    if(code.toInt()==SERVER_HAND_CODE)
    {
        if(m_server_hand.keys().contains(value))
        {
            m_server_hand.insert(value,QDateTime::currentDateTime());
        }
        else
        {
            search(addr.toIPv4Address());
        }
    }
    else if(code.toInt()==NEW_SERVER_CODE)
    {
        XMLObject xml;
        if(xml.load(value,0))
        {
            if(xml.get_title()==SERVER_TITLE)
            {
                tagServerInfo info;
                info.m_uuid=xml.get_property("uuid");
                info.m_server_version=xml.get_property("server_version");
                info.m_server_type=xml.get_property("server_type");
                info.m_server_ip=addr.toIPv4Address();
                if(info.m_uuid!="" && info.m_server_version!="")
                {
                    emit server_online(&info);
                    if(!m_server_hand.keys().contains(info.m_uuid))
                    {
                        search(addr.toIPv4Address());
                    }
                    m_server_hand.insert(info.m_uuid,QDateTime::currentDateTime());
                }
            }
        }
    }
    else if(code.toInt()==SERVER_OFFLINE_CODE)
    {
        if(m_server_hand.keys().contains(value))
        {
            emit server_offline(value);
            m_server_hand.remove(value);
        }
    }
}

void QDeviceClient::send_read()
{
    int size=m_send_recv_socket->pendingDatagramSize();
    if(size<=0)
    {
        return;
    }
    QHostAddress addr;
    char *data=new char[size+1];
    m_send_recv_socket->readDatagram(data,size,&addr);
    data[size]=0;
    QByteArray recv=QByteArray(data,size);
    emit recv_data(recv);
    delete data;
}

void QDeviceClient::hand_timer()
{
    QDateTime dt=QDateTime::currentDateTime();

    QMapIterator<QString,QDateTime> it(m_server_hand);

    QStringList list;

    while(it.hasNext())
    {
        it.next();
        if(it.value().msecsTo(dt)>HAND_TIME_OUT)
        {
            list.append(it.key());
        }
    }

    foreach(const QString &str,list)
    {
        emit server_offline(str);
        m_server_hand.remove(str);
    }

    if(m_last_send_time.msecsTo(QDateTime::currentDateTime())>1000)
    {
        QString str=QString::number(DEVICE_HAND_CODE)+":"+m_device_info->m_uuid;
        m_socket->writeDatagram(str.toLocal8Bit(),QHostAddress::Broadcast,CLIENT_HAND_WRITE);

        if(m_device_info->m_project_name!="")
        {

            QList<QAbstractProperty*> pros=m_device_info->m_project_core->get_project_host()->get_propertys();

            XMLObject xml;
            xml.set_title("Device_Property");
            XMLObject *temp;
            foreach(QAbstractProperty* pro,pros)
            {
                if(pro->get_attribute(ATTR_NEED_UPDATE).toBool())
                {
                    temp=new XMLObject(&xml);
                    temp->set_title("Property");

                    temp->set_property("name",pro->get_attribute("show_name").toString());
                    temp->set_property("value",pro->get_value_text());
                }
            }
            str=QString::number(PROPERTY_CODE)+":"+m_device_info->m_uuid+":"+xml.write();
            m_socket->writeDatagram(str.toLocal8Bit(),QHostAddress::Broadcast,CLIENT_HAND_WRITE);
        }

        m_last_send_time=QDateTime::currentDateTime();
    }
}

void QDeviceClient::search(int addr)
{
    XMLObject xml;
    xml.set_simple();
    xml.set_title("Device");
    xml.set_property("uuid",m_device_info->m_uuid);
    xml.set_property("device_type",m_device_info->m_device_type);
    xml.set_property("project_name",m_device_info->m_project_name);
    xml.set_property("soft_version",m_device_info->m_soft_version);
    xml.set_property("soft_status",m_device_info->m_soft_status);
    QString str=QString::number(NEW_DEVICE_CODE)+":"+xml.write();
    m_socket->writeDatagram(str.toLocal8Bit(),addr!=-1?QHostAddress(addr):QHostAddress::Broadcast,CLIENT_HAND_WRITE);
}

void QDeviceClient::send_data(const QByteArray &data, int addr)
{
    m_send_recv_socket->writeDatagram(data,addr==-1?QHostAddress::Broadcast:QHostAddress(addr),CLIENT_WRITE);
}
